package net.takela.common.spring.http;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.http.config.Registry;
import org.apache.hc.core5.http.config.RegistryBuilder;
import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.apache.hc.core5.ssl.TrustStrategy;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
 * @author baboy
 * create at 2023/1/22
 */
public class HttpRequestTemplate extends RestTemplate{
    private boolean verifyCa;
    private InputStream keyStoreInputStream;
    private String caAlias;
    private PoolingHttpClientConnectionManager connectionManagerInstance;
    /**
     * 
     */
    public HttpRequestTemplate(){

    }
    /**
     * 
     */
    public HttpRequestTemplate(boolean verifyCa, InputStream keyStoreInputStream, String caAlias){
        this.verifyCa = verifyCa;
        this.keyStoreInputStream = keyStoreInputStream;
        this.caAlias = caAlias;
    }


    /**
     * 获取(密钥及证书)仓库
     * 注:该仓库用于存放 密钥以及证书
     * @return 密钥、证书 仓库
     * @throws KeyStoreException 异常信息
     * @throws CertificateException 异常信息
     * @throws IOException 异常信息
     * @throws NoSuchAlgorithmException 异常信息
     * create at 2019/6/11 18:48
     */
    private KeyStore getKeyStore()
            throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
        // 证书工厂
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        // 秘钥仓库
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null);
        keyStore.setCertificateEntry(caAlias, certificateFactory.generateCertificate(keyStoreInputStream));
        return keyStore;
    }
    private SSLConnectionSocketFactory getSSLConnectionSocketFactory() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException {
        X509TrustManager x509TrustManager;
        // https请求，需要校验证书
        if (verifyCa) {
            KeyStore keyStore = getKeyStore();
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
            if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
                throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
            }
            x509TrustManager = (X509TrustManager) trustManagers[0];
            // 这里传TLS或SSL其实都可以的
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{x509TrustManager}, new SecureRandom());
            return new SSLConnectionSocketFactory(sslContext);
        }
//        SSLContext sslContext = SSLContext.getInstance("TLS");
//        // https请求，不作证书校验
//        x509TrustManager = new X509TrustManager() {
//            @Override
//            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
//
//            }
//            @Override
//            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
//
//            }
//            @Override
//            public X509Certificate[] getAcceptedIssuers() {
//                return new X509Certificate[0];
//            }
//        };
//        sslContext.init(null, new TrustManager[]{x509TrustManager}, new SecureRandom());
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
            
    /**
     * 
     */
    @Override
            public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                return true;
            }
        }).build();
        return new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
    }
    /**
     * 
     */
    public synchronized PoolingHttpClientConnectionManager getConnectionManager(){
        if (connectionManagerInstance != null){
            return connectionManagerInstance;
        }
        Registry<ConnectionSocketFactory> registry
                = null;
        try {
            registry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", PlainConnectionSocketFactory.INSTANCE)
            .register("https", getSSLConnectionSocketFactory())
            .build();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        PoolingHttpClientConnectionManager connectionManager = new
                PoolingHttpClientConnectionManager(registry);
        connectionManagerInstance = connectionManager;
        return connectionManager;
    }
    private CloseableHttpClient getHttpClient() {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create().setConnectionManager(getConnectionManager());

        CloseableHttpClient httpClient = httpClientBuilder.build();
        return httpClient;
    }
    private HttpComponentsClientHttpRequestFactory getClientHttpRequestFactory() {
        HttpClient httpClient = getHttpClient();
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory( httpClient);
        // httpClient连接配置
        // 连接超时
        clientHttpRequestFactory.setConnectTimeout(30 * 1000);

        // 数据读取超时时间
//        clientHttpRequestFactory.set.setReadTimeout(300 * 1000);
        // 连接不够用的等待时间
        clientHttpRequestFactory.setConnectionRequestTimeout(10 * 1000);
        return clientHttpRequestFactory;
    }
    /**
     * 
     */
    public void init(){
        this.setRequestFactory(this.getClientHttpRequestFactory());
    }
//    public static void main(String[] args){
//        HttpRequestTemplate requestTemplate = new HttpRequestTemplate();
//        restTemplate = new RestTemplate(requestTemplate.getClientHttpRequestFactory());
//        Map<String, String> requestHeaders = new HashMap();
//        Map<String, String>  params = new HashMap();
//        params.put("a","b");
//        requestTemplate.request(HttpMethod.GET, "http://www.baidu.com",requestHeaders,null, params);
//    }

}
